home *** CD-ROM | disk | FTP | other *** search
- /* mci_obuf.cpp
-
- Output buffer class for Win32 multimedia system written by
- Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Writing to Windows multimedia system with such a small
- buffer won't do, so we increase buffer size, and ignore
- most of the writes. Also we need to have a queue of 3 wave
- headers for smooth playback. The last header and the oldest
- header play while the current one is being filled in.
-
- Note that this does not support 8-bit soundcards yet! I don't
- know what the data format is to that */
-
- /* Changes since last version: changed GMEM_MOVEABLE to GMEM_FIXED
- which is a bit faster, according to the suggestions of Paul Forgey.
- clear_buffer() added for seeking. Changes int16 parameter to int32
- for minor speed improvement. Last edit: 06/29/96. */
-
- /* More changes: eliminated GlobalLock on the fixed memory, which
- is unnecessary.
-
- Added a function clear_buffer(), which clears the audio data
- when a seek is made by the user.
-
- Also added a function set_stop_flag() which
- sets a flag when playback is interrupted by the user. Then
- no attempt is made to unprepare headers after waveReset() is
- called by the main thread.
-
- Last edit: 10/12/96. */
-
- /* Replaced usage of the PCMWAVEFORMAT structure with the more up
- to date WAVEFORMATEX structure.
-
- According to the suggestions of Sergey Kuzmin, replaced
- GlobalAlloc and GlobalFree with new and delete, which should
- eliminate memory leaks.
-
- Last edit: 12/31/96. */
-
- #ifdef __WIN32__
- #define STRICT
- #define WIN32_LEAN_AND_MEAN
- #define NOMCX
- #define NOIME
- #define NOGDI
- #define NOUSER
- #define NOSOUND
- #define NOCOMM
- #define NODRIVERS
- #define OEMRESOURCE
- #define NONLS
- #define NOSERVICE
- #define NOKANJI
- #define NOMINMAX
- #define NOLOGERROR
- #define NOPROFILER
- #define NOMEMMGR
- #define NOLFILEIO
- #define NOOPENFILE
- #define NORESOURCE
- #define NOATOM
- #define NOLANGUAGE
- #define NOLSTRING
- #define NODBCS
- #define NOKEYBOARDINFO
- #define NOGDICAPMASKS
- #define NOCOLOR
- #define NOGDIOBJ
- #define NODRAWTEXT
- #define NOTEXTMETRIC
- #define NOSCALABLEFONT
- #define NOBITMAP
- #define NORASTEROPS
- #define NOMETAFILE
- #define NOSYSMETRICS
- #define NOSYSTEMPARAMSINFO
- #define NOMSG
- #define NOWINSTYLES
- #define NOWINOFFSETS
- #define NOSHOWWINDOW
- #define NODEFERWINDOWPOS
- #define NOVIRTUALKEYCODES
- #define NOKEYSTATES
- #define NOWH
- #define NOMENUS
- #define NOSCROLL
- #define NOCLIPBOARD
- #define NOICONS
- #define NOMB
- #define NOSYSCOMMANDS
- #define NOMDI
- #define NOCTLMGR
- #define NOWINMESSAGES
- #define NOHELP
- #define _WINUSER_
- #define __oleidl_h__
- #define _OLE2_H_
- #include <windows.h>
-
- #ifndef WIN32GUI
- #include <iostream.h>
- #endif
-
- #include "header.h"
- #include "args.h"
- #include "obuffer.h"
- #include "mci_obuf.h"
-
- MCIbuffer::MCIbuffer(uint32 number_of_channels,
- MPEG_Args *maplay_args)
- {
- channels = number_of_channels;
- data_size = channels * BUFFERSIZE;
-
- hdr_size = sizeof(WAVEHDR);
- lpwavehdr_arr = new LPWAVEHDR[3];
- phwo = maplay_args->phwo;
- fillup = 0;
-
- lpwf = (tWAVEFORMATEX *) new WAVEFORMATEX;
-
- lpwf->wBitsPerSample = 16; // No 8-bit support yet
- lpwf->wFormatTag = WAVE_FORMAT_PCM;
- lpwf->nChannels = (WORD) channels;
- lpwf->nSamplesPerSec = (DWORD) maplay_args->MPEGheader->frequency();
- lpwf->nAvgBytesPerSec = (DWORD) channels *
- maplay_args->MPEGheader->frequency() << 1;
- lpwf->nBlockAlign = (WORD) (channels << 1);
- lpwf->cbSize = 0;
-
- if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
- NULL, NULL, WAVE_ALLOWSYNC) != MMSYSERR_NOERROR)
- {
- #ifndef WIN32GUI
- cerr << endl << "Could not open wave device." << endl;
- #endif
- return;
- }
-
- buffer_count = 0;
-
- for(uint32 i=0; i<3; i++) {
- lpwavehdr_arr[i] = (LPWAVEHDR) new WAVEHDR;
-
- LPWAVEHDR temp = lpwavehdr_arr[i];
-
- if(!temp) return;
-
- temp->lpData = (LPSTR) new char[data_size];
-
- if(!temp->lpData) return;
- temp->dwBufferLength = data_size;
- temp->dwBytesRecorded = 0;
- temp->dwUser = 0; // If played, dwUser = 1
- temp->dwLoops = 0;
- temp->dwFlags = NULL;
- }
-
- for(uint32 i=0; i<channels; i++)
- bufferp[i] = i * channels;
-
- user_stop = 0;
- }
-
- void MCIbuffer::append (uint32 channel, int16 value)
- {
- // Need to break up the 32-bit integer into 2 8-bit bytes.
- // (ignore the first two bytes - either 0x0000 or 0xffff)
- // Note that Intel byte order is backwards!!!
-
- LPSTR temp = lpwavehdr_arr[2]->lpData;
-
- temp[bufferp[channel]] = (char) (value & 0xff);
- temp[bufferp[channel]+1] = (char) (value >> 8);
-
- bufferp[channel] += channels << 1;
-
- return;
- }
-
- #pragma argsused
- void MCIbuffer::write_buffer(int32 fd)
- {
- // Actually write only when buffer is actually full.
- if ((++buffer_count & BIT_SELECT) == 0) {
-
- buffer_count = 0;
-
- // Wait for 2 completed headers
- if (fillup > 1) {
-
- // Prepare & write newest header
- waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
- waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);
-
- // Header has now been sent
- lpwavehdr_arr[2]->dwUser = 1;
-
- wave_swap();
-
- // Unprepare oldest header
- if (lpwavehdr_arr[2]->dwUser) {
-
- while(waveOutUnprepareHeader(*phwo, lpwavehdr_arr[2],
- hdr_size) == WAVERR_STILLPLAYING)
- Sleep(SLEEPTIME);
- }
-
- } else {
-
- if (++fillup == 2) {
-
- // Write the previously calculated 2 headers
- waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
- waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
-
- // Header has now been sent
- lpwavehdr_arr[0]->dwUser = 1;
-
- wave_swap();
-
- waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
- waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
-
- // Header has now been sent
- lpwavehdr_arr[0]->dwUser = 1;
-
- } else {
- wave_swap();
- }
- }
-
- for(uint32 i=0; i<channels; i++)
- bufferp[i] = i * channels;
- }
- return;
- }
-
- void MCIbuffer::wave_swap()
- {
- LPWAVEHDR temp = lpwavehdr_arr[2];
- lpwavehdr_arr[2] = lpwavehdr_arr[1];
- lpwavehdr_arr[1] = lpwavehdr_arr[0];
- lpwavehdr_arr[0] = temp;
-
- return;
- }
-
- #ifdef SEEK_STOP
- void MCIbuffer::clear_buffer()
- // Clear all the data in the buffers
- {
-
- waveOutReset(*phwo);
-
- for(uint32 i=0; i<3; i++) {
-
- LPWAVEHDR temp = lpwavehdr_arr[i];
-
- if (temp->dwUser)
- waveOutUnprepareHeader(*phwo, temp, hdr_size);
-
- temp->dwUser = 0;
-
- for(uint32 j=0; j<data_size; j++)
- temp->lpData[j] = (char) 0;
- }
-
- // Reset buffer pointers
- for(uint32 i=0; i<channels; i++)
- bufferp[i] = i * channels;
-
- // Force the buffers to fillup before playing.
- fillup = buffer_count = 0;
- }
-
- void MCIbuffer::set_stop_flag()
- // Set the flag to avoid unpreparing non-existent headers
- {
- user_stop = 1;
- return;
- }
- #endif
-
-
- MCIbuffer::~MCIbuffer()
- {
- if (user_stop) {
-
- waveOutReset(*phwo);
-
- } else {
-
- if (fillup == 1) {
-
- // Write the last header calculated (at the top of the array).
- waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
- waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
-
- // Header has been written.
- lpwavehdr_arr[0]->dwUser = 1;
- }
-
- if (buffer_count) {
-
- /* Write the last wave header (probably not be written due to buffer size
- increase.) */
-
- for(uint32 i = bufferp[channels-1]; i < data_size; i++)
- lpwavehdr_arr[2]->lpData[i] = (char) 0;
-
- waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
- waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);
-
- // Header has been written.
- lpwavehdr_arr[2]->dwUser = 1;
- wave_swap();
- }
- }
-
- // Unprepare and free the header memory.
- for (int32 j=2; j>=0; j--) {
- if (lpwavehdr_arr[j]->dwUser && !user_stop)
- while (waveOutUnprepareHeader(*phwo, lpwavehdr_arr[j], hdr_size)
- == WAVERR_STILLPLAYING)
- Sleep(SLEEPTIME);
-
- delete [] lpwavehdr_arr[j]->lpData;
- delete lpwavehdr_arr[j];
- }
-
- delete [] lpwavehdr_arr;
- delete lpwf;
-
-
- while(waveOutClose(*phwo) == WAVERR_STILLPLAYING);
- Sleep(SLEEPTIME);
-
- return;
- }
-
- Obuffer *create_obuffer(MPEG_Args *maplay_args)
- {
- Obuffer *buffer;
-
- enum e_mode mode = maplay_args->MPEGheader->mode();
- enum e_channels which_channels = maplay_args->which_c;
-
- if ((mode == single_channel) || (which_channels != both))
- buffer = new MCIbuffer(1, maplay_args); // mono
- else
- buffer = new MCIbuffer(2, maplay_args); // stereo
-
- return(buffer);
- }
-
- #endif // __WIN32__
-